﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Management;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Convertor.Interface;
using Wpf.CommonTools;
using Wpf.CommonTools.SystemExtension;
using Wpf.CommonTools.NumberExtension;

namespace Convertor
{
    [Serializable]
    public class Config : ICloneable, INotifyPropertyChanged
    {
        #region Static ReadOnly Variable

        public const string DOWNLOAD_URL = "https://convertfactory.codeplex.com/releases";
        public const string HELP_URL = "https://convertfactory.codeplex.com/documentation";
        public const string TEMPLATE_URL = "https://convertfactory.codeplex.com/releases/view/107271";

        public static readonly string StartConfigPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Convertor", "StartConfig.xml"); // Application's configuarations
        public static readonly string SystemTemplatePath = System.IO.Path.Combine(System.Windows.Forms.Application.StartupPath, "SystemTemplate");

        #endregion

        #region Static Vsariable

        /// <summary>
        /// 
        /// </summary>
        public static Config GlobalConfig = new Config();
        private static string configPath;
        /// <summary>
        /// 
        /// </summary>
        public static string ConfigPath
        {
            get { return Config.configPath ?? (Config.configPath = System.IO.Path.Combine(GlobalConfig.WorkspacePath, @"config.xml")); }
        }
        private static string tempPluginsSavePath;
        /// <summary>
        /// Tempory saved the selected plug-in, use for next apps start to load it
        /// </summary>
        public static string TempPluginsSavePath
        {
            get { return Config.tempPluginsSavePath ?? (tempPluginsSavePath = System.IO.Path.Combine(GlobalConfig.WorkspacePath, @"temp.dat")); }
        }
        private static string logPath;
        /// <summary>
        /// Log saved path
        /// </summary>
        public static string LogPath
        {
            get { return Config.logPath ?? (Config.logPath = System.IO.Path.Combine(GlobalConfig.WorkspacePath, "log_" + DateTime.Now.ToString("yyyyMM") + ".txt")); }
        }
        private static string inputHistoryPath;
        /// <summary>
        /// History saved path, not finished right now
        /// </summary>
        public static string InputHistoryPath
        {
            get { return Config.inputHistoryPath ?? (Config.inputHistoryPath = System.IO.Path.Combine(GlobalConfig.WorkspacePath, "History.data")); }
        }
        private readonly ObservableCollection<ITemplateToLoadViewModel> templateList = new ObservableCollection<ITemplateToLoadViewModel>();
        /// <summary>
        /// All template list
        /// </summary>
        public ObservableCollection<ITemplateToLoadViewModel> TemplateList
        {
            get { return templateList; }
        }
        private static TemplateViewModel currentTemplate = new TemplateViewModel();
        /// <summary>
        /// Selected template which is loaded from disk
        /// </summary>
        public static TemplateViewModel CurrentTemplate
        {
            get { return Config.currentTemplate; }
            set { Config.currentTemplate = value; }
        }
        private static IPluginsItemCollection currentPlugin = new PluginsItemCollection();
        /// <summary>
        /// Selected plug-ins
        /// </summary>
        public static IPluginsItemCollection CurrentPlugin
        {
            get { return Config.currentPlugin; }
            set { Config.currentPlugin = value; }
        }
        private static LogViewModel logModel = new LogViewModel();
        /// <summary>
        /// Convert log list
        /// </summary>
        public static LogViewModel LogModel
        {
            get { return Config.logModel; }
            set { Config.logModel = value; }
        }
        private static PrcessingPluginViewModel procesingPluginNameModel = new PrcessingPluginViewModel();
        /// <summary>
        /// Current converting plug-in
        /// </summary>
        public static PrcessingPluginViewModel ProcesingPluginNameModel
        {
            get { return Config.procesingPluginNameModel; }
            set { Config.procesingPluginNameModel = value; }
        }
        private static HelpViewModel helpContent;
        /// <summary>
        /// Help view model in About Us windows
        /// </summary>
        public static HelpViewModel HelpContent
        {
            get { return helpContent ?? (helpContent = getHelpContent()); }
        }
        /// <summary>
        /// Copy a plug-in to paste
        /// </summary>
        public static PluginItem CopiedPlugin;
        /// <summary>
        /// 
        /// </summary>
        public static bool SafeModel { get; set; }
        /// <summary>
        /// Application's args
        /// </summary>
        public static string[] Args { get; set; }

        #endregion

        #region To Save Properities

        /// <summary>
        /// Get or set output content save whether automatically to clipboard
        /// </summary>
        private bool outputToClipboard;
        public bool OutputToClipboard
        {
            get { return outputToClipboard; }
            set { outputToClipboard = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("OutputToClipboard")); } }
        }
        private bool autoOutput;
        /// <summary>
        /// Get or set Auto output content
        /// The app will automatically output when Input content is changed
        /// </summary>
        public bool AutoOutput
        {
            get { return autoOutput; }
            set { autoOutput = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("AutoOutput")); } }
        }
        private int rightTabIndex = 1;
        /// <summary>
        /// 
        /// </summary>
        public int RightTabIndex
        {
            get { return rightTabIndex; }
            set
            {
                if (rightTabIndex != value)
                {
                    rightTabIndex = value;
                    if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("RightTabIndex")); }
                }
            }
        }
        private int leftTabIndex = 1;
        /// <summary>
        /// 
        /// </summary>
        public int LeftTabIndex
        {
            get { return leftTabIndex; }
            set
            {
                if (leftTabIndex != value)
                {
                    leftTabIndex = value;
                    if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("LeftTabIndex")); }
                }
            }
        }
        private int bottomTabIndex;
        /// <summary>
        /// 
        /// </summary>
        public int BottomTabIndex
        {
            get { return bottomTabIndex; }
            set
            {
                if (bottomTabIndex != value)
                {
                    bottomTabIndex = value;
                    if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("BottomTabIndex")); }
                }
            }
        }
        private int newTemplateCount;
        /// <summary>
        /// 
        /// </summary>
        public int NewTemplateCount
        {
            get { return newTemplateCount; }
            set { newTemplateCount = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("NewTemplateCount")); } }
        }
        private string userId;
        /// <summary>
        /// 
        /// </summary>
        public string UserId
        {
            get { return userId ?? (userId = getMac()); }
            set { userId = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("UserId")); } }
        }
        private double verticalChange = 200;
        /// <summary>
        /// 
        /// </summary>
        public double VerticalChange
        {
            get { return verticalChange; }
            set { verticalChange = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("VerticalChange")); } }
        }
        private double leftChange = 190;
        /// <summary>
        /// 
        /// </summary>
        public double LeftChange
        {
            get { return leftChange; }
            set { leftChange = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("LeftChange")); } }
        }
        private double managePluginHorizontalChange = 200;
        /// <summary>
        /// 
        /// </summary>
        public double ManagePluginHorizontalChange
        {
            get { return managePluginHorizontalChange; }
            set { managePluginHorizontalChange = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("ManagePluginHorizontalChange")); } }
        }
        private int pluginType;
        /// <summary>
        /// Get or set current selected Plugin type
        /// </summary>
        public int PluginType
        {
            get { return pluginType; }
            set
            {
                if (value != -1 && value != pluginType)
                {
                    pluginType = value;
                    if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("PluginType")); }
                }
            }
        }
        private DateTime lastCheckedUpdate = DateTime.MinValue;
        /// <summary>
        /// 
        /// </summary>
        public DateTime LastCheckedUpdate
        {
            get { return lastCheckedUpdate; }
            set { lastCheckedUpdate = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("LastCheckedUpdate")); } }
        }
        private UpdateIntervalTypes checkUpdateInterval = UpdateIntervalTypes.OneDay;
        /// <summary>
        /// 
        /// </summary>
        public UpdateIntervalTypes CheckUpdateInterval
        {
            get { return checkUpdateInterval; }
            set { checkUpdateInterval = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("CheckUpdateInterval")); } }
        }
        private bool hasUpdate;
        /// <summary>
        /// Is true the application has new version
        /// </summary>
        public bool HasUpdate
        {
            get { return hasUpdate; }
            set { hasUpdate = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("HasUpdate")); } }
        }
        private string language;
        /// <summary>
        /// Application's UI language
        /// </summary>
        public string Language
        {
            get { return language; }
            set { language = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("Language")); } }
        }
        private bool enableEscToCloseChildWindows = true;
        /// <summary>
        /// Enable using ESC to quit the windows which is poped up by main windows
        /// </summary>
        public bool EnableEscToCloseChildWindows
        {
            get { return enableEscToCloseChildWindows; }
            set { enableEscToCloseChildWindows = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("EnableEscToCloseChildWindows")); } }
        }
        private bool ignoreLog;
        /// <summary>
        /// 
        /// </summary>
        public bool IgnoreLog
        {
            get { return ignoreLog; }
            set { ignoreLog = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("IgnoreLog")); } }
        }
        private bool useWebExplorer = true;
        /// <summary>
        /// 
        /// </summary>
        public bool UseWebExplorer
        {
            get { return useWebExplorer; }
            set { useWebExplorer = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("UseWebExplorer")); } }
        }
        private int templateType;
        /// <summary>
        /// 
        /// </summary>
        public int TemplateType
        {
            get { return templateType; }
            set
            {
                if (value != -1 && templateType != value)
                {
                    templateType = value;
                    if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("TemplateType")); }
                }
            }
        }

        #endregion

        #region Properities

        private string workspacePath;
        /// <summary>
        /// 
        /// </summary>
        public string WorkspacePath
        {
            get { return workspacePath ?? (workspacePath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Convertor")); }
            set
            {
                workspacePath = value;
                if (!workspacePathList.Contains(workspacePath))
                {
                    workspacePathList.Add(workspacePath);
                }
                if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("WorkSpacePath")); }
            }
        }

        /// <summary>
        /// The application will pop up update windows if true
        /// </summary>
        public bool NeedUpdate
        {
            get { return (DateTime.Now - Config.GlobalConfig.LastCheckedUpdate).TotalDays >= (int)Config.GlobalConfig.CheckUpdateInterval; }
        }
        private bool isConvertingStop = true;
        /// <summary>
        /// 
        /// </summary>
        public bool IsConvertingStop
        {
            get { return isConvertingStop; }
            set { isConvertingStop = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("IsConvertingStop")); } }
        }
        private string convertedContent;

        public string ConvertedContent
        {
            get { return convertedContent; }
            set { convertedContent = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("ConvertedContent")); } }
        }
        private string lastInputContent;

        public string LastInputContent
        {
            get { return lastInputContent; }
            set { lastInputContent = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("LastInputContent")); } }
        }
        private string durringTime;

        public string DurringTime
        {
            get { return durringTime; }
            set { durringTime = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("DurringTime")); } }
        }
        /// <summary>
        /// 
        /// </summary>
        private int exceptionTime;

        public int ExceptionTime
        {
            get { return exceptionTime; }
            set { exceptionTime = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("ExceptionTime")); } }
        }
        private readonly ObservableCollection<string> disabledPlugins = new ObservableCollection<string>();
        /// <summary>
        /// Disabled plugin list, saved the key of plugin
        /// </summary>
        public ObservableCollection<string> DisabledPlugins
        {
            get { return disabledPlugins; }
            set
            {
                disabledPlugins.Clear();
                foreach (var v in value)
                {
                    disabledPlugins.Add(v);
                }
            }
        }
        private readonly ObservableCollection<string> workspacePathList = new ObservableCollection<string>();
        /// <summary>
        /// 
        /// </summary>
        public ObservableCollection<string> WorkspacePathList
        {
            get
            {
                if (workspacePathList.Count == 0)
                {
                    workspacePathList.Add(WorkspacePath);
                }
                return workspacePathList;
            }
            set
            {
                workspacePathList.Clear();
                foreach (var v in value)
                {
                    workspacePathList.Add(v);
                }
            }
        }
        private ObservableDictionary<string, object> allPlugins = new ObservableDictionary<string, object>();
        /// <summary>
        /// All Original Plugins
        /// </summary>
        public ObservableDictionary<string, object> AllPlugins
        {
            get { return allPlugins; }
            set { allPlugins = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("AllPlugins")); } }
        }

        #endregion

        #region Public Function

        static Config()
        {
        }

        public Config()
        {
            disabledPlugins.CollectionChanged += disabledPlugins_CollectionChanged;
            templateList.CollectionChanged += templateList_CollectionChanged;
            allPlugins.CollectionChanged += allPlugins_CollectionChanged;
        }

        public void Reset()
        {
            Config c = new Config();
            this.AutoOutput = c.AutoOutput;
            this.BottomTabIndex = c.BottomTabIndex;
            this.CheckUpdateInterval = c.CheckUpdateInterval;
            this.ConvertedContent = c.ConvertedContent;
            this.DisabledPlugins = c.DisabledPlugins;
            this.EnableEscToCloseChildWindows = c.EnableEscToCloseChildWindows;
            this.HasUpdate = c.HasUpdate;
            this.IgnoreLog = c.IgnoreLog;
            this.Language = c.Language;
            this.LastCheckedUpdate = c.LastCheckedUpdate;
            this.LastInputContent = c.LastInputContent;
            this.LeftChange = c.LeftChange;
            this.LeftTabIndex = c.LeftTabIndex;
            this.ManagePluginHorizontalChange = c.ManagePluginHorizontalChange;
            this.NewTemplateCount = c.NewTemplateCount;
            this.OutputToClipboard = c.OutputToClipboard;
            this.PluginType = c.PluginType;
            this.RightTabIndex = c.RightTabIndex;
            this.TemplateType = c.TemplateType;
            this.UserId = c.UserId;
            this.UseWebExplorer = c.UseWebExplorer;
            this.VerticalChange = c.VerticalChange;
        }

        #endregion

        #region Private Functions

        private static string getMac()
        {
            string MacAddr = null;
            ManagementObjectSearcher Query = new ManagementObjectSearcher("select * from Win32_NetworkAdapterConfiguration");
            ManagementObjectCollection QueryCollection = Query.Get();
            foreach (ManagementObject mo in QueryCollection)
            {
                if (mo["IPEnabled"].ToString() == "True")
                    MacAddr = mo["MacAddress"].ToString();
            }
            return (MacAddr);
        }

        private static HelpViewModel getHelpContent()
        {
            HelpViewModel model = new HelpViewModel();
            model.MachineName = System.Net.Dns.GetHostName();
            model.Version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
            model.CompanyName = ((AssemblyCompanyAttribute)Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), typeof(AssemblyCompanyAttribute), false)).Company;
            return model;
        }

        private void disabledPlugins_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("DisabledPlugins"));
            }
        }

        void templateList_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("TemplateList"));
                PropertyChanged(this, new PropertyChangedEventArgs("TemplateType"));
            }
        }

        void allPlugins_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("PluginType"));
                PropertyChanged(this, new PropertyChangedEventArgs("DisabledPlugins"));
            }
        }

        #endregion

        #region ICloneable 成员

        public object Clone()
        {
            Config a = new Config()
            {
                AutoOutput = this.AutoOutput,
                BottomTabIndex = this.BottomTabIndex,
                CheckUpdateInterval = this.CheckUpdateInterval,
                EnableEscToCloseChildWindows = this.EnableEscToCloseChildWindows,
                HasUpdate = this.HasUpdate,
                Language = this.Language,
                LeftTabIndex = this.LeftTabIndex,
                LastCheckedUpdate = this.LastCheckedUpdate,
                NewTemplateCount = this.NewTemplateCount,
                OutputToClipboard = this.OutputToClipboard,
                PluginType = this.PluginType,
                RightTabIndex = this.RightTabIndex,
                TemplateType = this.TemplateType,
                UserId = this.UserId,
                VerticalChange = this.VerticalChange,
                WorkspacePath = this.WorkspacePath,
            };
            return a;
        }

        #endregion

        #region INotifyPropertyChanged 成员

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }
}
